#region Imported Namespaces


using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

using AvalonDock;

using WtfManager.Controls;
using WtfManager.Framework;


#endregion


namespace WtfManager.UIManager.Commands
{
  ///<summary>
  /// Contains handlers for <see cref="ApplicationCommands"/>
  ///</summary>
  public abstract class OpenCommandHandlerBase: ExtensibleService, ICommandHandler
  {
    #region Fields


    private UIService _uiService;


    #endregion


    #region Constructors/Finalizers


    ///<summary>
    /// OpenCommandHandlerBase default constructor.
    ///</summary>
    internal OpenCommandHandlerBase()
    {
    }


    #endregion


    #region Properties/Indexers


    public abstract ICommand Command
    {
      get;
    }


    #endregion


    #region Methods


    protected override void OnStateChnaged()
    {
      if (IsInitialized)
      {
        _uiService = (UIService)WtfFramework.Instance.Services[typeof(UIService)];
      }
      else
      {
        _uiService = null;
      }
    }


    protected override FrameworkComponentState OnLoad()
    {
      AddDependency(typeof(UIService));

      return FrameworkComponentState.Loaded;
    }


    protected override void OnUnload()
    {
      _uiService = null;
    }


    ///<summary>
    /// Determines whether a specified extension is valid.
    ///</summary>
    ///<param name="extension">An extension to check.</param>
    ///<returns>True, if a specified extension is valid, otherwise false.</returns>
    public override bool IsExtension(Service extension)
    {
      return extension is IContentItemLauncherExtension || extension is IParentItemProvider;
    }


    ///<summary>
    /// Called when extension was added.
    ///</summary>
    protected override void OnExtensionAdded(Service extension)
    {
    }


    ///<summary>
    /// Called when an extension was removed.
    ///</summary>
    protected override void OnExtensionRemoved(Service extension)
    {
    }


    ///<summary>
    /// Determines whether a handled command can be executed.
    ///</summary>
    public bool CanExecuteCommand(object sender, object parameter)
    {
      Debug.Assert(IsInitialized, "OpenCommandHandlerBase is not yet initialized.");

      List<object> itemsToOpen = GetItemsToOpen(parameter, sender as FrameworkElement);

      return itemsToOpen.Count != 0 && CanExecute(itemsToOpen);
    }


    protected static object GetCurrentDocumentItem()
    {
      ManagedContent activeDocument = GetActiveDocument();
      return activeDocument.GetContent();
    }


    protected abstract bool CanExecute(List<object> itemsToOpen);


    protected bool CanLaunch(object item)
    {
      foreach (Service service in Extensions)
      {
        if (!(service is IContentItemLauncherExtension))
        {
          continue;
        }

        var extension = (IContentItemLauncherExtension)service;

        if (extension.CanLaunch(item))
        {
          return true;
        }
      }

      return false;
    }


    protected bool CanOpenInCurrentTab(object item)
    {
      ManagedContent currentContentViewer = GetActiveDocument();
      return CanOpen(item, currentContentViewer);
    }


    private bool CanOpen(object item, ContentControl contentControl)
    {
      if (item == null || contentControl == null)
      {
        return false;
      }

      UIControlInfo controlInfo = _uiService.GetContentContainer(item.GetType());

      return controlInfo != null && controlInfo.IsOfType(contentControl.GetType());
    }


    protected bool CanOpenInNewTab(object item)
    {
      if (item == null)
      {
        return false;
      }

      UIControlInfo controlInfo = _uiService.GetContentContainer(item.GetType());

      return controlInfo != null;
    }


    /// <summary>
    /// Executes command.
    /// </summary>
    public void ExecuteCommand(object sender, object parameter)
    {
      Debug.Assert(IsInitialized, "OpenCommandHandlerBase is not yet initialized.");

      List<object> itemsToOpen = GetItemsToOpen(parameter, sender as FrameworkElement);

      Execute(itemsToOpen);
    }


    protected abstract void Execute(List<object> itemsToOpen);


    private void LaunchItem(object item)
    {
      foreach (Service service in Extensions)
      {
        if (!(service is IContentItemLauncherExtension))
        {
          continue;
        }

        var extension = (IContentItemLauncherExtension)service;

        if (!extension.CanLaunch(item))
        {
          continue;
        }

        extension.Launch(item);
        return;
      }
    }


    private void OpenInNewContainer(object content)
    {
      DockingManager dockingManager = WtfDockingManager.CurrentDockingManager;
      ManagedContent activeDocument = GetActiveDocument();
      Pane pane;
      int newDocumentIndex;

      if (activeDocument != null)
      {
        pane = activeDocument.ContainerPane;
        newDocumentIndex = pane.Items.IndexOf(activeDocument) + 1;
      }
      else
      {
        pane = dockingManager.MainDocumentPane;
        newDocumentIndex = pane.Items.Count;
      }

      UIControlInfo controlInfo = _uiService.GetContentContainer(content.GetType());
      var contentControl = (ContentControl)controlInfo.CreateInstance();

      pane.Items.Insert(newDocumentIndex, contentControl);

      SetContent(contentControl, content);
    }


    private static void SetContent(ContentControl contentControl, object content)
    {
      if (contentControl is WtfDocumentContent)
      {
        var documentContent = (WtfDocumentContent)contentControl;
        documentContent.Data = content;
      }
      else
      {
        var control = (ContentControl)contentControl.Content;
        control.Content = content;
      }
    }


    private static ManagedContent GetActiveDocument()
    {
      if (WtfDockingManager.CurrentDockingManager == null)
      {
        return null;
      }

      ManagedContent activeDocument = WtfDockingManager.CurrentDockingManager.ActiveDocument;

      if (activeDocument == null || activeDocument.ContainerPane == null)
      {
        return null;
      }

      return activeDocument;
    }


    private static List<object> GetItemsToOpen(object parameter, FrameworkElement frameworkElement)
    {
      if (parameter != null)
      {
        return GetItemsToOpenFromParameter(parameter);
      }

      return frameworkElement != null ? frameworkElement.GetDataItems() : new List<object>();
    }


    private static List<object> GetItemsToOpenFromParameter(object parameter)
    {
      var itemsToOpen = new List<object>();

      if (parameter is OpenCommandParameters)
      {
        var commandParameters = (OpenCommandParameters)parameter;

        if (commandParameters.ItemsToOpen is IEnumerable)
        {
          foreach (object item in (IEnumerable)commandParameters.ItemsToOpen)
          {
            itemsToOpen.Add(item);
          }

          return itemsToOpen;
        }

        if (commandParameters.ItemsToOpen == null)
        {
          return new List<object>();
        }

        itemsToOpen.Add(commandParameters.ItemsToOpen);

        return itemsToOpen;
      }

      itemsToOpen.Add(parameter);

      return itemsToOpen;
    }


    protected object GetParentItem(object item)
    {
      foreach (Service service in Extensions)
      {
        if (service is IParentItemProvider)
        {
          var parentItemResolver = (IParentItemProvider)service;
          object parent = parentItemResolver.GetParent(item);

          if (parent != null)
          {
            return parent;
          }
        }
      }

      return null;
    }


    protected override FrameworkComponentState OnInitialize()
    {
      return FrameworkComponentState.Initialized;
    }


    protected bool Launch(object item)
    {
      if (CanLaunch(item))
      {
        LaunchItem(item);

        return true;
      }
      return false;
    }


    protected bool OpenInCurrentTab(object item)
    {
      ManagedContent currentContentViewer = GetActiveDocument();

      if (CanOpen(item, currentContentViewer))
      {
        SetContent(currentContentViewer, item);

        return true;
      }

      return false;
    }


    protected bool OpenInNewTab(object item)
    {
      if (CanOpenInNewTab(item))
      {
        OpenInNewContainer(item);

        return true;
      }

      return false;
    }


    #endregion
  }
}